#include "cexcept.h"
#include "type.h"
#include "rpc_serial.h"
#warning Not sure which of the two serial.h this should include

/****************************************************************************/
// Parameters

#define NUM_FUNCNAME_CHARS 20 // Maximum function name length

#define MAX_LINK_ERRS ( 2 ) // Maximum number of framing errors before connection reset

#define LUARPC_MODE "elua"

// a kind of silly way to get the maximum int, but oh well ...
#define MAXINT ((int)((((unsigned int)(-1)) << 1) >> 1))

/****************************************************************************/
// Debug Error Handling

// allow special handling for GCC compiler
#ifdef __GNUC__
#define DOGCC(x) x
#else
#define DOGCC(x) /* */
#endif

// Assertions for debug mode
#ifdef LUARPC_DEBUG
#ifdef __GNUC__
#define MYASSERT(a) if (!(a)) rpcdebug ( \
  "assertion \"" #a "\" failed in %s() [%s]",__FUNCTION__,__FILE__);
#else
#define MYASSERT(a) if (!(a)) rpcdebug ( \
  "assertion \"" #a "\" failed in %s:%d",__FILE__,__LINE__);
#endif
#else
#define MYASSERT(a) ;
#endif

//****************************************************************************
// Error Messages & Exceptions

#ifdef WIN32_BUILD
#include "windows.h"
#define transport_strerror strerror
#define transport_errno (GetLastError())
#else
#define transport_errno errno
#define transport_strerror strerror
#endif

// error numbers passed around are normal system "errno" error numbers
//  (normally generated by transport operations), except when they have the
//  following values:

enum {
  ERR_EOF       = MAXINT - 100,  // reached end of file on transport
  ERR_CLOSED    = MAXINT - 101,  // attempted operation on closed transport
  ERR_PROTOCOL  = MAXINT - 102,  // some error in the received protocol
  ERR_NODATA    = MAXINT - 103,
  ERR_COMMAND   = MAXINT - 106,
  ERR_HEADER    = MAXINT - 107,
  ERR_LONGFNAME = MAXINT - 108
};

enum exception_type { done, nonfatal, fatal };

struct exception {
  enum exception_type type;
  int errnum;
};

define_exception_type(struct exception);

extern struct exception_context the_exception_context[ 1 ];

//****************************************************************************
// LuaRPC Structures

// Transport Connection Structure
typedef struct _Transport Transport;
struct _Transport 
{
  ser_handler fd;
  unsigned tmr_id;
  u8     loc_little: 1,               // Local is little endian?
         loc_armflt: 1,               // local float representation is arm float?
         loc_intnum: 1,               // Local is integer only?
         net_little: 1,               // Network is little endian?
         net_intnum: 1;               // Network is integer only?
  u8     lnum_bytes;
};

typedef struct _Handle Handle;
struct _Handle 
{
  Transport tpt;                      // the handle socket
  int error_handler;                  // function reference
  int async;                          // nonzero if async mode being used
  int read_reply_count;               // number of async call return values to read
};

typedef struct _Helper Helper;
struct _Helper {
  Handle *handle;                         // pointer to handle object
  Helper *parent;                         // parent helper
  int pref;                               // Parent reference idx in registry
  u8 nparents;                            // number of parents
  char funcname[NUM_FUNCNAME_CHARS + 1];  // name of the function
};

typedef struct _ServerHandle ServerHandle;
struct _ServerHandle {
  Transport ltpt;   // listening transport, always valid if no error
  Transport atpt;   // accepting transport, valid if connection established
  int link_errs;
};


// Connection State Checking
#ifdef WIN32_BUILD
#define INVALID_TRANSPORT (INVALID_HANDLE_VALUE)
#else
#define INVALID_TRANSPORT (-1)
#endif

#define TRANSPORT_VERIFY_OPEN \
  if (tpt->fd == INVALID_TRANSPORT) \
  { \
    e.errnum = ERR_CLOSED; \
    e.type = fatal; \
    Throw( e ); \
  }

// Arg & Error Checking Provided to Transport Mechanisms 
int check_num_args (lua_State *L, int desired_n);
void deal_with_error (lua_State *L, Handle *h, const char *error_string);
void my_lua_error( lua_State *L, const char *errmsg );

// TRANSPORT API 

// Setup Transport 
void transport_init (Transport *tpt);

// Open Listener / Server 
void transport_open_listener(lua_State *L, ServerHandle *handle);

// Open Connection / Client 
int transport_open_connection(lua_State *L, Handle *handle);

// Accept Connection 
void transport_accept (Transport *tpt, Transport *atpt);

// Read & Write to Transport 
void transport_read_buffer (Transport *tpt, u8 *buffer, int length);
void transport_write_buffer (Transport *tpt, const u8 *buffer, int length);

// Check if data is available on connection without reading:
//     - 1 = data available, 0 = no data available
int transport_readable (Transport *tpt);

// Check if transport is open:
//    - 1 = connection open, 0 = connection closed
int transport_is_open (Transport *tpt);

// Shut down connection
void transport_close (Transport *tpt);
